#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <cassert>
namespace mylog
{
#define BUFFER_DEFAULT_SIZE (1 * 1024 * 1024)
#define BUFFER_INCREMENT_SIZE (1 * 1024 * 1024)
#define BUFFER_THRESHOLD_SIZE (10 * 1024 * 1024)
    class Buffer
    {
    public:
        Buffer() : _reader_idx(0), _write_idx(0), _buffer(BUFFER_DEFAULT_SIZE) {}
        bool Empty() { return _reader_idx == _write_idx; }
        size_t ReadAbleSize() { return _write_idx - _reader_idx; }
        size_t WriteAbleSize() { return _buffer.size() - _write_idx; }
        void Reset() { _reader_idx = _write_idx = 0; }
        void Swap(Buffer &buf)
        {
            _buffer.swap(buf._buffer);
            std::swap(_reader_idx, buf._reader_idx);
            std::swap(_write_idx, buf._write_idx);
        }
        void Push(const char *data, size_t len)
        {
            assert(len <= WriteAbleSize());
            EnsureEnoughSpace(len);
            std::copy(data, data + len, &_buffer[_write_idx]);
            _write_idx += len;
        }
        const char *Begin() { return &_buffer[_reader_idx]; }
        void Pop(size_t len)
        {
            _reader_idx += len;
            assert(_reader_idx <= _write_idx);
        }

    protected:
        void EnsureEnoughSpace(size_t len)
        {
            if (len <= WriteAbleSize())
                return;
            size_t new_capacity;
            if (_buffer.size() < BUFFER_THRESHOLD_SIZE)
            {
                new_capacity = _buffer.size() * 2 + len;
            }
            else
            {
                new_capacity = _buffer.size() + BUFFER_INCREMENT_SIZE + len;
            }
            _buffer.resize(new_capacity);
        }

    private:
        size_t _reader_idx;
        size_t _write_idx;
        std::vector<char> _buffer;
    };
};